use std::process::{Command, Stdio};
use tokio::sync::mpsc;
use serde::{Deserialize, Serialize};
use thiserror::Error;

#[derive(Debug, Error)]
pub enum FfmpegError {
    #[error("FFmpeg not found: {0}")]
    FfmpegNotFound(String),
    #[error("Input file not found: {0}")]
    InputFileNotFound(String),
    #[error("Output file already exists: {0}")]
    OutputFileExists(String),
    #[error("Unsupported format: {0}")]
    UnsupportedFormat(String),
    #[error("Invalid parameter: {0}")]
    InvalidParameter(String),
    #[error("Processing failed: {0}")]
    ProcessingFailed(String),
    #[error("IO error: {0}")]
    IoError(String),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FfmpegProgress {
    pub progress: f32,
    pub time_processed: String,
    pub current_speed: String,
    pub eta: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VideoFormat {
    pub name: String,
    pub extension: String,
    pub supported_codecs: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AudioFormat {
    pub name: String,
    pub extension: String,
    pub supported_bitrates: Vec<u32>,
}

#[derive(Clone)]
pub struct FfmpegService {
    ffmpeg_path: String,
}

impl FfmpegService {
    pub fn new() -> Result<Self, FfmpegError> {
        // 检测系统中可用的 FFmpeg 路径
        let ffmpeg_path = Self::find_ffmpeg()?;
        
        Ok(Self { ffmpeg_path })
    }
    
    fn find_ffmpeg() -> Result<String, FfmpegError> {
        // 首先检查环境变量
        if let Ok(custom_path) = std::env::var("FFMPEG_PATH") {
            if Self::test_ffmpeg_path(&custom_path) {
                return Ok(custom_path);
            }
        }

        // 预定义的路径列表（包含用户自定义路径）
        let possible_paths = [
            "D:\\Program Files\\ffmpeg\\bin\\ffmpeg.exe",  // 用户自定义路径
            "ffmpeg",
            "ffmpeg.exe",
            "/usr/bin/ffmpeg",
            "/usr/local/bin/ffmpeg",
            "C:\\Program Files\\ffmpeg\\bin\\ffmpeg.exe",
            "C:\\ffmpeg\\bin\\ffmpeg.exe",
            "C:\\tools\\ffmpeg\\bin\\ffmpeg.exe",
        ];

        for path in possible_paths.iter() {
            if Self::test_ffmpeg_path(path) {
                return Ok(path.to_string());
            }
        }

        Err(FfmpegError::FfmpegNotFound(
            "FFmpeg not found in system PATH or common locations. Please install FFmpeg or set FFMPEG_PATH environment variable.".to_string()
        ))
    }

    fn test_ffmpeg_path(path: &str) -> bool {
        Command::new(path)
            .arg("-version")
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .status()
            .is_ok()
    }

    pub fn get_ffmpeg_path(&self) -> &str {
        &self.ffmpeg_path
    }

    pub fn get_ffmpeg_version(&self) -> Result<String, FfmpegError> {
        let output = Command::new(&self.ffmpeg_path)
            .arg("-version")
            .output()
            .map_err(|e| FfmpegError::IoError(e.to_string()))?;

        if output.status.success() {
            let version_output = String::from_utf8_lossy(&output.stdout);
            if let Some(line) = version_output.lines().next() {
                Ok(line.to_string())
            } else {
                Ok("Unknown version".to_string())
            }
        } else {
            Err(FfmpegError::ProcessingFailed("Failed to get FFmpeg version".to_string()))
        }
    }
    
    pub fn get_supported_video_formats() -> Vec<VideoFormat> {
        vec![
            VideoFormat {
                name: "MP4".to_string(),
                extension: "mp4".to_string(),
                supported_codecs: vec!["h264".to_string(), "h265".to_string(), "vp9".to_string()],
            },
            VideoFormat {
                name: "AVI".to_string(),
                extension: "avi".to_string(),
                supported_codecs: vec!["mpeg4".to_string(), "xvid".to_string()],
            },
            VideoFormat {
                name: "MOV".to_string(),
                extension: "mov".to_string(),
                supported_codecs: vec!["h264".to_string(), "prores".to_string()],
            },
            VideoFormat {
                name: "MKV".to_string(),
                extension: "mkv".to_string(),
                supported_codecs: vec!["h264".to_string(), "h265".to_string(), "vp9".to_string()],
            },
            VideoFormat {
                name: "WMV".to_string(),
                extension: "wmv".to_string(),
                supported_codecs: vec!["wmv2".to_string()],
            },
        ]
    }
    
    pub fn get_supported_audio_formats() -> Vec<AudioFormat> {
        vec![
            AudioFormat {
                name: "MP3".to_string(),
                extension: "mp3".to_string(),
                supported_bitrates: vec![128, 192, 256, 320],
            },
            AudioFormat {
                name: "WAV".to_string(),
                extension: "wav".to_string(),
                supported_bitrates: vec![1411], // CD quality
            },
            AudioFormat {
                name: "AAC".to_string(),
                extension: "aac".to_string(),
                supported_bitrates: vec![128, 192, 256, 320],
            },
            AudioFormat {
                name: "FLAC".to_string(),
                extension: "flac".to_string(),
                supported_bitrates: vec![], // Variable bitrate
            },
        ]
    }
    
    pub async fn convert_video(
        &self,
        input_path: &str,
        output_path: &str,
        format: &str,
        quality: Option<u32>,
        bitrate: Option<u32>,
        resolution: Option<(u32, u32)>,
        _progress_tx: Option<mpsc::Sender<FfmpegProgress>>,
    ) -> Result<(), FfmpegError> {
        // 验证输入文件存在
        if !std::path::Path::new(input_path).exists() {
            return Err(FfmpegError::InputFileNotFound(input_path.to_string()));
        }
        
        // 验证输出目录存在
        let output_dir = std::path::Path::new(output_path).parent()
            .ok_or_else(|| FfmpegError::InvalidParameter("Invalid output path".to_string()))?;
        
        if !output_dir.exists() {
            std::fs::create_dir_all(output_dir)
                .map_err(|e| FfmpegError::IoError(e.to_string()))?;
        }
        
        // 构建 FFmpeg 命令
        let mut cmd = Command::new(&self.ffmpeg_path);
        cmd.arg("-i").arg(input_path);
        
        // 添加格式相关参数
        match format.to_lowercase().as_str() {
            "mp4" => {
                cmd.arg("-c:v").arg("libx264");
                cmd.arg("-c:a").arg("aac");
            }
            "avi" => {
                cmd.arg("-c:v").arg("mpeg4");
                cmd.arg("-c:a").arg("mp3");
            }
            "mov" => {
                cmd.arg("-c:v").arg("libx264");
                cmd.arg("-c:a").arg("aac");
            }
            "mkv" => {
                cmd.arg("-c:v").arg("libx264");
                cmd.arg("-c:a").arg("aac");
            }
            "wmv" => {
                cmd.arg("-c:v").arg("wmv2");
                cmd.arg("-c:a").arg("wmav2");
            }
            _ => return Err(FfmpegError::UnsupportedFormat(format.to_string())),
        }
        
        // 添加质量参数
        if let Some(q) = quality {
            cmd.arg("-crf").arg(q.to_string());
        }
        
        // 添加码率参数
        if let Some(b) = bitrate {
            cmd.arg("-b:v").arg(format!("{}k", b));
        }
        
        // 添加分辨率参数
        if let Some((width, height)) = resolution {
            cmd.arg("-s").arg(format!("{}x{}", width, height));
        }
        
        // 添加输出参数
        cmd.arg("-y") // 覆盖输出文件
            .arg(output_path);
        
        // 执行命令
        let output = cmd.output()
            .map_err(|e| FfmpegError::IoError(e.to_string()))?;
        
        if !output.status.success() {
            let error_msg = String::from_utf8_lossy(&output.stderr);
            return Err(FfmpegError::ProcessingFailed(error_msg.to_string()));
        }
        
        Ok(())
    }
    
    pub async fn extract_audio(
        &self,
        video_path: &str,
        audio_path: &str,
        audio_format: &str,
        bitrate: Option<u32>,
        sample_rate: Option<u32>,
    ) -> Result<(), FfmpegError> {
        if !std::path::Path::new(video_path).exists() {
            return Err(FfmpegError::InputFileNotFound(video_path.to_string()));
        }
        
        let mut cmd = Command::new(&self.ffmpeg_path);
        cmd.arg("-i").arg(video_path)
            .arg("-vn") // 禁用视频流
            .arg("-y"); // 覆盖输出文件
        
        match audio_format.to_lowercase().as_str() {
            "mp3" => {
                cmd.arg("-c:a").arg("libmp3lame");
                if let Some(br) = bitrate {
                    cmd.arg("-b:a").arg(format!("{}k", br));
                }
            }
            "wav" => {
                cmd.arg("-c:a").arg("pcm_s16le");
            }
            "aac" => {
                cmd.arg("-c:a").arg("aac");
                if let Some(br) = bitrate {
                    cmd.arg("-b:a").arg(format!("{}k", br));
                }
            }
            _ => return Err(FfmpegError::UnsupportedFormat(audio_format.to_string())),
        }
        
        if let Some(sr) = sample_rate {
            cmd.arg("-ar").arg(sr.to_string());
        }
        
        cmd.arg(audio_path);
        
        let output = cmd.output()
            .map_err(|e| FfmpegError::IoError(e.to_string()))?;
        
        if !output.status.success() {
            let error_msg = String::from_utf8_lossy(&output.stderr);
            return Err(FfmpegError::ProcessingFailed(error_msg.to_string()));
        }
        
        Ok(())
    }
    
    pub fn get_video_info(&self, file_path: &str) -> Result<serde_json::Value, FfmpegError> {
        if !std::path::Path::new(file_path).exists() {
            return Err(FfmpegError::InputFileNotFound(file_path.to_string()));
        }
        
        let output = Command::new(&self.ffmpeg_path)
            .arg("-i")
            .arg(file_path)
            .stderr(Stdio::piped())
            .output()
            .map_err(|e| FfmpegError::IoError(e.to_string()))?;
        
        let stderr = String::from_utf8_lossy(&output.stderr);
        
        // 解析 FFmpeg 输出以获取视频信息
        let mut duration = None;
        let mut bitrate = None;
        let mut resolution = None;
        let mut codec = None;
        let mut fps = None;
        
        for line in stderr.lines() {
            if line.contains("Duration") {
                if let Some(duration_str) = line.split("Duration:").nth(1) {
                    if let Some(duration_part) = duration_str.split(',').next() {
                        duration = Some(duration_part.trim().to_string());
                    }
                }
            } else if line.contains("Video:") {
                if let Some(video_info) = line.split("Video:").nth(1) {
                    // 解析编码器
                    if let Some(codec_part) = video_info.split(',').next() {
                        codec = Some(codec_part.trim().to_string());
                    }
                    
                    // 解析分辨率
                    if let Some(res_part) = video_info.split(',').find(|s| s.contains("x")) {
                        let res_clean = res_part.trim()
                            .split_whitespace()
                            .find(|s| s.contains('x'))
                            .unwrap_or("");
                        resolution = Some(res_clean.to_string());
                    }
                    
                    // 解析帧率
                    if let Some(fps_part) = video_info.split(',').find(|s| s.contains("fps")) {
                        fps = Some(fps_part.trim().to_string());
                    }
                }
            } else if line.contains("bitrate:") {
                if let Some(bitrate_part) = line.split("bitrate:").nth(1) {
                    bitrate = Some(bitrate_part.trim().to_string());
                }
            }
        }
        
        let file_size = std::fs::metadata(file_path)
            .map(|m| m.len())
            .unwrap_or(0);
        
        let info = serde_json::json!({
            "file_path": file_path,
            "file_size": file_size,
            "duration": duration,
            "bitrate": bitrate,
            "resolution": resolution,
            "codec": codec,
            "fps": fps,
        });
        
        Ok(info)
    }
}